#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 文件名称: auth_api.py
# 文件保存路径: backend/api/miniprogram/auth_api.py
"""
微信小程序认证API
实现微信登录、用户绑定、JWT Token管理等功能
"""

from flask import request, jsonify
from flask_jwt_extended import create_access_token, jwt_required, get_jwt_identity
import requests
from datetime import timedelta, datetime
from backend.infrastructure.database import db
from backend.models.user import User
from backend.models.student import Student
from backend.api.miniprogram import miniprogram_bp
from backend.services.unified_log_service import UnifiedLogService
import os
import time

# 创建统一日志服务实例
log_service = UnifiedLogService()

# 微信小程序配置（需要从环境变量获取）
WECHAT_APPID = os.getenv('WECHAT_APPID', 'wx9d3d2db7e7c5707a')  # 从环境变量获取，默认使用项目配置的AppID
WECHAT_SECRET = os.getenv('WECHAT_SECRET', 'your_secret_here')  # 需要配置实际的微信小程序Secret

def generate_token(openid):
    """
    生成JWT token
    """
    try:
        # 查找或创建用户
        user = User.query.filter_by(openid=openid).first()
        if not user:
            # 创建新用户（小程序用户不需要密码）
            user = User(
                openid=openid,
                username=f'微信用户_{openid[-8:]}',
                password_hash='',  # 小程序用户不需要密码
                user_type='miniprogram',
                bind_status='unbound'
            )
            db.session.add(user)
            db.session.commit()
            print(f"创建新用户: {user.id}")
        
        # 生成JWT token
        token = create_access_token(
            identity=str(user.id),  # JWT identity必须是字符串
            expires_delta=timedelta(days=30)
        )
        
        print(f"生成token成功: {token[:20]}...")
        return token
    except Exception as e:
        print(f"生成token失败: {e}")
        import traceback
        traceback.print_exc()
        return None

@miniprogram_bp.route('/health', methods=['GET'])
def health_check():
    """
    微信小程序API健康检查接口
    """
    return jsonify({
        'success': True,
        'message': '微信小程序API服务正常',
        'timestamp': datetime.now().isoformat()
    })

@miniprogram_bp.route('/test', methods=['GET'])
def test_endpoint():
    """
    微信小程序API测试接口
    """
    return jsonify({
        'success': True,
        'message': 'miniprogram API test endpoint working',
        'data': {
            'version': '1.0.0',
            'environment': 'production',
            'timestamp': datetime.now().isoformat()
        }
    })

@miniprogram_bp.route('/auth/login', methods=['POST'])
def wechat_login():
    """微信小程序登录接口"""
    try:
        data = request.get_json()
        if not data or 'code' not in data:
            return jsonify({
                'success': False,
                'message': '缺少登录凭证code'
            }), 400
        
        code = data['code']
        if not code:
            return jsonify({
                'success': False,
                'message': '缺少登录凭证code'
            }), 400
        
        # 开发模式：如果code是测试code，直接返回模拟数据
        if code == 'test_code_123' or code.startswith('test_'):
            # 模拟登录成功
            mock_openid = 'mock_openid_' + str(int(time.time()))
            
            # 为开发模式生成真实的JWT token
            token = generate_token(mock_openid)
            if not token:
                return jsonify({
                    'success': False,
                    'message': '开发模式token生成失败'
                }), 500
            
            return jsonify({
                'success': True,
                'data': {
                    'token': token,
                    'openid': mock_openid,
                    'message': '开发模式登录成功'
                }
            })
        
        # 生产模式：调用微信API
        try:
            # 调用微信登录API
            url = f"https://api.weixin.qq.com/sns/jscode2session?appid={WECHAT_APPID}&secret={WECHAT_SECRET}&js_code={code}&grant_type=authorization_code"
            response = requests.get(url, timeout=10)
            result = response.json()
            
            if 'errcode' in result:
                return jsonify({
                    'success': False,
                    'message': f'微信登录失败: {result.get("errmsg", "未知错误")}'
                }), 400
            
            openid = result.get('openid')
            session_key = result.get('session_key')
            
            if not openid:
                return jsonify({
                    'success': False,
                    'message': '微信登录失败: 未获取到openid'
                }), 400
            
            # 生成JWT token
            token = generate_token(openid)
            
            return jsonify({
                'success': True,
                'data': {
                    'token': token,
                    'openid': openid
                }
            })
            
        except requests.exceptions.RequestException as e:
            return jsonify({
                'success': False,
                'message': f'微信API调用失败: {str(e)}'
            }), 400
            
    except Exception as e:
        return jsonify({
            'success': False,
            'message': f'登录失败: {str(e)}'
        }), 500

@miniprogram_bp.route('/auth/bind', methods=['POST'])
@jwt_required()
def bind_student():
    """
    用户绑定学生接口
    家长用户绑定自己的孩子
    """
    try:
        print("=== 绑定学生API开始 ===")
        current_user_id = get_jwt_identity()
        print(f"JWT identity: {current_user_id}, type: {type(current_user_id)}")
        
        # JWT identity是字符串，需要转换为整数
        user = User.query.get(int(current_user_id))
        print(f"查找到的用户: {user}")

        if not user:
            print("用户不存在")
            return jsonify({
                'success': False,
                'message': '用户不存在'
            }), 404

        data = request.get_json()
        print(f"接收到的数据: {data}")

        education_id = data.get('education_id')
        student_name = data.get('student_name')
        parent_phone = data.get('parent_phone')

        print(f"解析的字段: education_id={education_id}, student_name={student_name}, parent_phone={parent_phone}")
        
        if not all([education_id, student_name, parent_phone]):
            print("缺少必要参数")
            return jsonify({
                'success': False,
                'message': '缺少必要参数'
            }), 400

        # 查找学生
        student = Student.query.filter_by(education_id=education_id).first()
        
        if not student:
            return jsonify({
                'success': False,
                'message': '未找到该学生，请确认教育ID号是否正确'
            }), 404

        # 验证家长信息
        if student.parent_phone != parent_phone:
            return jsonify({
                'success': False,
                'message': '家长电话不匹配，请确认信息是否正确'
            }), 400

        # 更新用户绑定状态
        user.bind_status = 'confirmed'
        user.student_id = student.id

        # 自动升级为家长角色
        from backend.models.role import Role
        from backend.models.user_role import UserRole

        # 获取家长角色
        parent_role = Role.query.filter_by(name='parent').first()
        if parent_role:
            # 检查用户是否已有家长角色
            existing_parent_role = UserRole.query.filter_by(
                user_id=int(current_user_id),
                role_id=parent_role.id
            ).first()

            if not existing_parent_role:
                # 分配家长角色
                user_role = UserRole(user_id=int(current_user_id), role_id=parent_role.id)
                db.session.add(user_role)
                print(f"自动分配家长角色给用户: {current_user_id}")

        db.session.commit()

        # 记录绑定操作日志
        log_service.log_student_operation(
            student_id=student.id,
            action='UPDATE',
            operation_data={'bind_user_id': user.id, 'student_name': student.name},
            operator=f'用户{user.id}',
            ip_address=request.remote_addr
        )

        return jsonify({
            'success': True,
            'data': {
                'user_id': user.id,
                'username': user.username,
                'user_type': user.user_type,
                'bind_status': user.bind_status,
                'student_id': student.id,
                'student_name': student.name,
                'student': {
                    'id': student.id,
                    'name': student.name,
                    'education_id': student.education_id
                }
            },
            'message': '绑定成功'
        })

    except Exception as e:
        print(f"绑定异常: {str(e)}")
        import traceback
        traceback.print_exc()
        db.session.rollback()
        return jsonify({
            'success': False,
            'message': f'绑定失败: {str(e)}'
        }), 500

@miniprogram_bp.route('/auth/profile', methods=['GET'])
@jwt_required()
def get_user_profile():
    """
    获取用户信息接口
    """
    try:
        from flask import current_app
        raw_identity = get_jwt_identity()
        current_app.logger.debug(f"[PROFILE] raw_identity={raw_identity!r}")
        # 尝试解析为整数ID
        user_id = None
        if isinstance(raw_identity, int):
            user_id = raw_identity
        else:
            try:
                user_id = int(str(raw_identity))
            except Exception as conv_e:
                current_app.logger.error(f"[PROFILE] identity_convert_fail identity={raw_identity!r} error={conv_e}")
                return jsonify({
                    'success': False,
                    'message': '无效的身份令牌'
                }), 400

        user = User.query.get(user_id)
        if not user:
            current_app.logger.warning(f"[PROFILE] user_not_found user_id={user_id}")
        
        if not user:
            return jsonify({
                'success': False,
                'message': '用户不存在'
            }), 404
        
        profile_data = {
            'user_id': user.id,
            'username': user.username,
            'user_type': user.user_type,
            'bind_status': user.bind_status,
            'student_id': user.student_id,
            'created_at': user.created_at.isoformat() if user.created_at else None
        }
        
        # 如果已绑定学生，返回学生信息
        if user.student_id:
            student = Student.query.get(user.student_id)
            if student:
                profile_data['student'] = {
                    'id': student.id,
                    'name': student.name,
                    'education_id': student.education_id,
                    'school': student.school,
                    'class_name': student.class_name,
                    'gender': student.gender,
                    'parent_name': student.parent_name,
                    'parent_phone': student.parent_phone
                }
                try:
                    from backend.models.student_extension import StudentExtension
                    latest_extension = StudentExtension.query.filter_by(
                        student_id=student.id
                    ).order_by(StudentExtension.data_year.desc()).first()
                    if latest_extension:
                        profile_data['student']['grade'] = latest_extension.grade
                        profile_data['student']['data_year'] = latest_extension.data_year
                except Exception as ext_e:
                    current_app.logger.error(f"[PROFILE] extension_query_fail student_id={student.id} error={ext_e}")
        
        return jsonify({
            'success': True,
            'data': profile_data,
            'message': '获取用户信息成功'
        })
        
    except Exception as e:
        from flask import current_app
        import traceback
        current_app.logger.error(f"[PROFILE] unexpected_error error={e}\n{traceback.format_exc(limit=5)}")
        return jsonify({
            'success': False,
            'message': '获取用户信息失败: 服务器内部错误'
        }), 500


@miniprogram_bp.route('/auth/phone_login', methods=['POST'])
def phone_login():
    """手机号+密码登录接口"""
    try:
        data = request.get_json()
        if not data:
            return jsonify({
                'success': False,
                'message': '缺少请求数据'
            }), 400
        
        phone = data.get('phone')
        password = data.get('password')
        
        if not phone or not password:
            return jsonify({
                'success': False,
                'message': '手机号和密码不能为空'
            }), 400
        
        # 验证手机号格式
        import re
        if not re.match(r'^1[3-9]\d{9}$', phone):
            return jsonify({
                'success': False,
                'message': '手机号格式不正确'
            }), 400
        
        # 查找用户（使用mobile字段）
        from werkzeug.security import check_password_hash
        from sqlalchemy.exc import OperationalError
        try:
            user = User.query.filter_by(mobile=phone).first()
        except OperationalError:
            return jsonify({'success': False, 'message': '数据库暂时不可用，请稍后再试', 'error': 'db_connect_failed'}), 503
        
        if not user:
            return jsonify({
                'success': False,
                'message': '用户不存在'
            }), 401
        
        # 验证密码
        if not check_password_hash(user.password_hash, password):
            return jsonify({
                'success': False,
                'message': '密码错误'
            }), 401
        
        # 生成JWT token
        token = create_access_token(
            identity=str(user.id),
            expires_delta=timedelta(days=30)
        )
        
        # 准备用户信息
        user_info = {
            'id': user.id,
            'username': user.username,
            'phone': user.mobile,
            'user_type': user.user_type,
            'bind_status': user.bind_status
        }
        
        return jsonify({
            'success': True,
            'data': {
                'token': token,
                'userInfo': user_info
            },
            'message': '登录成功'
        })
        
    except Exception as e:
        print(f"手机登录失败: {e}")
        import traceback
        traceback.print_exc()
        return jsonify({
            'success': False,
            'message': f'登录失败: {str(e)}'
        }), 500


@miniprogram_bp.route('/auth/register', methods=['POST'])
def phone_register():
    """手机号注册接口"""
    try:
        data = request.get_json()
        if not data:
            return jsonify({
                'success': False,
                'message': '缺少请求数据'
            }), 400
        
        phone = data.get('phone')
        password = data.get('password')
        sms_code = data.get('code')  # 前端发送的字段名是code
        real_name = data.get('realName', '')  # 获取真实姓名
        
        if not all([phone, password, sms_code]):
            return jsonify({
                'success': False,
                'message': '手机号、密码和验证码不能为空'
            }), 400
        
        # 验证手机号格式
        import re
        if not re.match(r'^1[3-9]\d{9}$', phone):
            return jsonify({
                'success': False,
                'message': '手机号格式不正确'
            }), 400
        
        # 验证密码长度
        if len(password) < 6:
            return jsonify({
                'success': False,
                'message': '密码至少6位'
            }), 400
        
        # 开发阶段：验证码验证（任意4位数字都可以通过）
        if len(sms_code) != 4 or not sms_code.isdigit():
            return jsonify({
                'success': False,
                'message': '请输入4位数字验证码'
            }), 400
        
        # 开发阶段：跳过真实短信验证码验证
        # 任意4位数字都可以通过
        print(f"开发模式：验证码 {sms_code} 验证通过")
        
        # 检查用户是否已存在
        existing_user = User.query.filter_by(mobile=phone).first()
        if existing_user:
            return jsonify({
                'success': False,
                'message': '手机号已注册'
            }), 400
        
        # 创建新用户
        from werkzeug.security import generate_password_hash
        user = User(
            username=f'用户{phone[-4:]}',
            mobile=phone,
            password_hash=generate_password_hash(password),
            user_type='miniprogram',
            bind_status='unbound'
        )
        
        # 如果提供了真实姓名，设置真实姓名
        if real_name:
            user.real_name = real_name
        
        try:
            db.session.add(user)
            db.session.commit()
            
            # 自动分配registered_user角色
            from backend.models.role import Role
            from backend.models.user_role import UserRole
            registered_user_role = Role.query.filter_by(name='registered_user').first()
            if registered_user_role:
                ur = UserRole(user_id=user.id, role_id=registered_user_role.id)
                db.session.add(ur)
                db.session.commit()
                print(f"为移动端注册用户 {user.id} 自动分配 registered_user 角色")
            
        except Exception as e:
            db.session.rollback()
            print(f"用户注册失败: {e}")
            return jsonify({
                'success': False,
                'message': '注册失败，请重试'
            }), 500
        
        # 生成JWT token
        token = create_access_token(
            identity=str(user.id),
            expires_delta=timedelta(days=30)
        )
        
        # 准备用户信息
        user_info = {
            'id': user.id,
            'username': user.username,
            'phone': user.mobile,
            'real_name': getattr(user, 'real_name', '') or real_name,
            'user_type': user.user_type,
            'bind_status': user.bind_status
        }
        
        return jsonify({
            'success': True,
            'data': {
                'token': token,
                'userInfo': user_info
            },
            'message': '注册成功'
        })
        
    except Exception as e:
        print(f"手机注册失败: {e}")
        import traceback
        traceback.print_exc()
        return jsonify({
            'success': False,
            'message': f'注册失败: {str(e)}'
        }), 500


@miniprogram_bp.route('/auth/send_sms', methods=['POST'])
def send_sms_code():
    """发送短信验证码接口"""
    try:
        data = request.get_json()
        if not data:
            return jsonify({
                'success': False,
                'message': '缺少请求数据'
            }), 400
        
        phone = data.get('phone')
        if not phone:
            return jsonify({
                'success': False,
                'message': '手机号不能为空'
            }), 400
        
        # 验证手机号格式
        import re
        if not re.match(r'^1[3-9]\d{9}$', phone):
            return jsonify({
                'success': False,
                'message': '手机号格式不正确'
            }), 400
        
        # TODO: 实际发送短信验证码的逻辑
        # 开发阶段返回模拟成功
        return jsonify({
            'success': True,
            'message': '验证码发送成功',
            'data': {
                'phone': phone,
                'debug_code': '123456'  # 开发阶段显示验证码
            }
        })
        
    except Exception as e:
        print(f"发送短信失败: {e}")
        return jsonify({
            'success': False,
            'message': f'发送失败: {str(e)}'
        }), 500

@miniprogram_bp.route('/auth/create_test_user', methods=['POST'])
def create_test_user():
    """
    创建测试用户（仅用于开发环境）
    """
    try:
        from werkzeug.security import generate_password_hash
        
        # 检查是否已存在测试用户
        existing_user = User.query.filter_by(mobile='13800138000').first()
        if existing_user:
            return jsonify({
                'success': True,
                'message': '测试用户已存在',
                'data': {
                    'user_id': existing_user.id,
                    'phone': existing_user.mobile
                }
            })
        
        # 创建测试用户
        test_user = User(
            username='test_parent',
            password_hash=generate_password_hash('123456'),
            mobile='13800138000',
            real_name='测试家长',
            user_type='miniprogram',
            bind_status='unbound',
            status='active'
        )
        
        db.session.add(test_user)
        db.session.commit()
        
        return jsonify({
            'success': True,
            'message': '测试用户创建成功',
            'data': {
                'user_id': test_user.id,
                'phone': test_user.mobile
            }
        })
        
    except Exception as e:
        db.session.rollback()
        return jsonify({
            'success': False,
            'message': f'创建测试用户失败: {str(e)}'
        }), 500

 